/**
 * @file SnakerMap.h
 */

#pragma once
#include "MainInclude.h"
#include "SnakerFruit.h"
// using namespace std;

/**
 * @brief 储存地图的下级单元
 * @param cx chunk在主要地图中的定位
 * @param cy chunk在主要地图中的定位
 * @param data 用来真正储存地图内容的单元
 * @param fruitList 将data中的水果ID与水果对象挂钩
 */
class SnakerChunk {
   public:
    int cx, cy;
    // int xmin, ymin, xmax, ymax;
    int data[chunkSize][chunkSize];
    std::vector<SnakerFruit*> fruitList;
    std::vector<bool> bookFruitList;
    // SnakerChunk(int, int, int, int, int, int);
    /**
     * @brief 构造函数
     */
    SnakerChunk(int, int);
};


/**
 * @brief 地图
 * @param chunkMap 将chunk与其绝对位置挂钩
 * 
 * 用红黑树储存chunk标记
 */
class SnakerMap {
   public:
    std::map<std::pair<int, int>, SnakerChunk*> chunkMap;  // [x][y]
    // int xMin, yMax, xMax, yMin;
    // int cxMin, cxMax, cyMin, cyMax;
    /**
     * @brief 获得原点chunk
     * 
     * 用于游戏初始化
     */
    SnakerChunk* mapOrigin();                     // chunkMap[Vector2(0, 0)]
    // bool hasChunkRow(int);
    /**
     * @brief 判断chunk坐标有无已生成的chunk
     * 
     * 避免访问空内存的唯一途径
     */
    bool hasChunk(int cx, int cy);                    // c-
    /**
     * @brief 根据chunk坐标获得chunk
     * @return 已知宏观坐标的chunk
     */
    SnakerChunk* FindChunk(int cx, int cy);           // c-
    // list<list<SnakerChunk*>>::iterator FindChunkRow(int);
    // SnakerChunk* FindChunk(int);
    /**
     * @brief 判断给定点是否在给定chunk中
     */
    bool inChunk(int x, int y, SnakerChunk* chk);
    // SnakerChunk* GetChunk(int, int, int, int, int, int);
    /**
     * @brief 根据给定点坐标获得chunk
     * @return 已知微观坐标的chunk
     */
    SnakerChunk* GetChunk(int x, int y);            // raw-
    /**
     * @brief 得到给定点上的水果对象
     */
    SnakerFruit* GetFruit(SnakerChunk*, int);
    /**
     * @brief 列出指定chunk中的所有水果
     * @warning 已被取代，不再使用！
     */
    std::vector<SnakerFruit*> ListFruit(SnakerChunk* chk);
    // vector<SnakerFruit*> ListFruit(int, int, int, int);
    // vector<SnakerFruit*> ListFruit();
    /**
     * @brief 获取给定点坐标在指定chunk的地形
     * @return 0为墙壁\n-1为地面\n正整数为水果
     */
    int GetTerrainType(int x, int y, SnakerChunk* chk);
    /**
     * @brief 获取给定点坐标的地形
     * @return 0为墙壁\n-1为地面\n正整数为水果
     * 
     * 会先寻找指定点所在chunk，如果有条件请在参数列表中给出寻找范围
     */
    int GetTerrainType(int x, int y);
    // void GenerateChunk(SnakerChunk&, const string);
    /**
     * @brief 生成原点区块
     */
    void GenerateMapOrigin();
    // void ExpandChunkRow(list<list<SnakerChunk*>>::iterator, int);
    /**
     * @brief 从给定区块向四周扩展生成新区块
     * 
     * 实际上是二层dfs
     */
    void ExpandMap(SnakerChunk* chk, bool EXP_FLG = true);
    /**
     * @brief 根据给出的参数在指定位置生成水果
     */
    void AddFruit(SnakerFruit* fruit, int x, int y);
    /**
     * @brief 移除指定位置的水果
     * @warning 不会判断指定位置是否为水果，需要在调用前自行判断
     */
    void RemoveFruit(int x, int y);
    /**
     * @brief 在指定区块随机生成水果
     * 
     * 生成上限为区块边长除以3
     */
    void GenerateFruit(SnakerChunk* chk, SnakerFruit* fruit);
    /**
     * @brief 初始化函数
     */
    void Init();
    /**
     * @brief 将指定区块以字符串形式打印
     * 
     * 用于调试
     */
    std::string DisplayChunk(SnakerChunk* chk);
    /**
     * @brief 将指定区块打印出来
     * @return 存有区块外形的二维字符数组
     */
    char** DisplayChunkC(SnakerChunk* chk);
    // void UpdateCanvas(int cx = canvasCx, int cy = canvasCy);
} snaker_stdmap;
// 260 259 258 261